package com.kcwl.idea.plugins.tool;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kcwl.idea.plugins.base.utils.CollUtil;
import com.kcwl.idea.plugins.base.utils.ResourceUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import org.apache.commons.lang.StringUtils;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 格式化视图
 *
 * @author xiehai1* @Copyright tellyes tech. inc. co.,ltd
 * @date 2018/10/12 16:02
 */
public class TextFormatView extends JRootPane {
    JPanel panel;
    Project project;
    /**
     * 菜单
     */
    Menu menu;

    /**
     * 菜单列表
     */
    List<JComboBox<Menu>> childMenus = new ArrayList<>();
    List<ComboBox<Menu>> mainMenus = new ArrayList<>();
    /**
     * 输入文本域
     */
    RSyntaxTextArea inputTextArea = new RSyntaxTextArea(19, 0);
    /**
     * 输出文本域
     */
    RSyntaxTextArea outputTextArea = new RSyntaxTextArea(34, 0);
    /**
     * cache instance by project
     */
    private static final Map<Project, TextFormatView> INSTANCES = new HashMap<>();

    private TextFormatView(Project project) {
        this.project = project;
        super.getContentPane().setLayout(new BoxLayout(super.getContentPane(), BoxLayout.Y_AXIS));
        // 初始化输入文本域
        this.doInitInputTextArea();
        // 初始化菜单
        this.doInitMenu();
        // 初始输出化文本域
        this.doInitOutputTextArea();
        // 设置高亮主题
        try (InputStream inputStream = this.getClass().getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/idea.xml")) {
            Theme theme = Theme.load(inputStream);
            theme.apply(this.inputTextArea);
            theme.apply(this.outputTextArea);
        } catch (IOException ignore) {
        }
    }

    /**
     * 输入文本域初始化
     */
    private void doInitInputTextArea() {
        this.inputTextArea.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), "format");
        this.inputTextArea.getActionMap().put("format", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                TextFormatView.this.doFormat();
            }
        });
        super.getContentPane().add(new RTextScrollPane(this.inputTextArea));
    }

    /**
     * 输出文本域初始化
     */
    private void doInitOutputTextArea() {
        this.outputTextArea.setCodeFoldingEnabled(true);
        this.outputTextArea.setAutoIndentEnabled(true);
        super.getContentPane().add(new RTextScrollPane(this.outputTextArea));
    }

    /**
     * 菜单初始化
     */
    private void doInitMenu() {
        panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        childMenus = new ArrayList<>();
        ItemListener changeMenuListener = e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                switchMenu((Menu) e.getItem());
            }
        };
        List<Menu> menus = listMenu();
        //主菜单
        JComboBox<Menu> mainMenu = new ComboBox<>();
        panel.add(mainMenu);

        int count = 0;
        for (Menu menu : menus) {
            mainMenu.addItem(menu);
            List<Menu> children = menu.getChildren();
            if (CollUtil.isEmpty(children)) {
                continue;
            }
            //子菜单
            JComboBox<Menu> childMenu = new ComboBox<>();
            for (Menu child : children) {
                childMenu.addItem(child);
            }
            childMenu.addItemListener(changeMenuListener);

            if (count == 0) {
                childMenu.setSelectedItem(0);
                childMenu.setVisible(true);
                this.switchMenu((Menu) childMenu.getSelectedItem());
            } else {
                childMenu.setVisible(false);
            }
            childMenus.add(childMenu);
            panel.add(childMenu);
            count++;
        }
        mainMenu.addItemListener(changeMenuListener);

        // 转换按钮
        JButton format = new JButton("转换");
        format.addActionListener(e -> doFormat());
        panel.add(format);

        super.getContentPane().add(panel);
    }

    /**
     * 菜单切换操作
     *
     * @param menu 菜单
     */
    private void switchMenu(Menu menu) {
        this.menu = menu;
        if (!CollUtil.isEmpty(this.menu.getChildren())) {
            for (JComboBox<Menu> childMenu : childMenus) {
                List<Menu> menus = listItemByComboBox(childMenu);
                if (menus.size() == 0) {
                    continue;
                }
                if (menus.get(0).getParentCode().equals(this.menu.getCode())) {
                    childMenu.setVisible(true);
                    this.menu = menus.get(0);
                } else {
                    childMenu.setVisible(false);
                }
            }
        }
        if (Objects.nonNull(this.inputTextArea)) {
            this.inputTextArea.setToolTipSupplier(null);
            this.inputTextArea.removeAllLineHighlights();
        }
    }

    /**
     * 格式化动作
     */
    private void doFormat() {
        // 文本框为空 不进行格式化
        if (StringUtils.isEmpty(this.inputTextArea.getText())) {
            return;
        }
        try {
            this.inputTextArea.setToolTipSupplier(null);
            this.inputTextArea.removeAllLineHighlights();

            String fullMethodName = menu.getAction();
            // 拆分类名和方法名
            String[] parts = fullMethodName.split("#");
            String className = parts[0];
            String methodName = parts[1];

            // 加载类
            Class<?> clazz = Class.forName(className);

            // 获取方法对象
            Method method = clazz.getMethod(methodName, Menu.class, RSyntaxTextArea.class, RSyntaxTextArea.class); // 假设参数为 String 和 int 类型

            // 创建实例（如果需要）
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // 调用方法
            method.invoke(instance, this.menu, this.inputTextArea, this.outputTextArea);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.getContentPane().repaint();
        }
    }

    /**
     * 按照{@link Project}单例
     *
     * @param project idea 项目
     * @return {@link TextFormatView}
     */
    static TextFormatView getInstance(Project project) {
        if (!INSTANCES.containsKey(project)) {
            synchronized (TextFormatView.class) {
                if (!INSTANCES.containsKey(project)) {
                    INSTANCES.putIfAbsent(project, new TextFormatView(project));
                }
            }
        }

        return INSTANCES.get(project);
    }


    private List<Menu> listItemByComboBox(JComboBox<Menu> comboBox) {
        ComboBoxModel model = comboBox.getModel();
        int itemCount = model.getSize();
        List<Menu> menus = new ArrayList<>();
        for (int i = 0; i < itemCount; i++) {
            menus.add((Menu) model.getElementAt(i));
        }
        return menus;
    }

    private List<Menu> listMenu() {
        List<Menu> menus = new ArrayList<>();
        try {
            String jsonString = ResourceUtil.loadAsString("tool-menus.json");
            ObjectMapper objectMapper = new ObjectMapper();
            menus = objectMapper.readValue(jsonString, new TypeReference<List<Menu>>() {
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return menus;
    }
}
